/** FASSIT (Forms of Selective Attention in Intelligent Transportation Systems)
 * Computational Creativity and Digital Media
 * Cognitive and Media Systems Group
 * Centre for Informatics and Systems of the University of Coimbra (CISUC)
 *
 * Copyright (c) 2010-2013 University of Coimbra, Portugal
 * All rights reserved.
 */
package androidLayer;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import masterAgent.Knowledge.MasterAgent;
import poi.Info.Location;
import poi.Info.POI;
import poi.Info.POIwithSAMetrics;
import poi.Surprise.Surprise;
import poi.Uncertainty.Uncertainty;
import agent.Context.Context;
import agent.Context.Goal;
import agent.Knowledge.Agent;
import agent.Metrics.Surprise.PastSurpriseValues;
import agent.Metrics.Surprise.SurpriseEvaluator;
import agent.Metrics.Uncertainty.PastUncertaintyValues;
import agent.Metrics.Uncertainty.UncertaintyEvaluator;
import androidLayer.Mysql.MysqlConnection;
import androidLayer.Mysql.MysqlManager;

/**
 * 
 * 
 * @author Hernani Costa
 * 
 * @version 0.2 date: 02/03/2013
 */
public class AndroidLayer implements Serializable {
	private static final long serialVersionUID = 1L;
	private MysqlManager mysqlManager;
	private PointsOfInterestByGoal expectationsByGoal;

	public AndroidLayer() {
		mysqlManager = new MysqlManager();
		expectationsByGoal = new PointsOfInterestByGoal();
	}

	/**
	 * The class is responsible for log the user and load the agent
	 * expectations.
	 * 
	 * @param email
	 *            - user email
	 * @param password
	 *            - user password
	 * @param context
	 *            - user context
	 * @return the Agent and the Master expectations for all the POIs in the
	 *         system
	 */
	public PointsOfInterestByGoal login(String email, String password, Context context) {
		email = mysqlManager.encodeEmail(email);
		boolean exists = mysqlManager.verifyUser(email, password);
		if (exists) {
			getAllPointsOfInterest(email, context);
			return expectationsByGoal;
		} else {
			mysqlManager.addUser(email, password);
			mysqlManager.createUserModel(email);
			getAllPointsOfInterest(email, context);
			return expectationsByGoal;
		}
	}

	private void getAllPointsOfInterest(String email, Context context) {
		Context cTemp = new Context(context.getLocation().getLatitude(), context.getLocation().getLongitude(), context.getTimeOfDay(), context.getDayOfWeek(), context.getGoal(), context.getRadius(), context.getRunID());
		for (String goal : new Goal().getAllGoals()) {
			cTemp.setGoal(goal);
			getListOfPois(email, cTemp);
		}
	}

	private void getListOfPois(String email, Context context) {
		Agent agent = new Agent();
		MasterAgent masterAgent = new MasterAgent();
		Surprise userModelSurpriseKnowledge = new Surprise();
		SurpriseEvaluator sEvaluator = SurpriseEvaluator.getInstance();
		Uncertainty userModelUncertaintyKnowledge = new Uncertainty();
		UncertaintyEvaluator uEvaluator = UncertaintyEvaluator.getInstance();
		HashMap<Integer, POIwithSAMetrics> poisNearTheAgentWithMASAValues = new HashMap<Integer, POIwithSAMetrics>();
		HashMap<Integer, POIwithSAMetrics> userModelTemp = new HashMap<Integer, POIwithSAMetrics>();
		HashMap<Integer, POI> noisyPOIs = new HashMap<Integer, POI>();
		HashMap<Integer, POIwithSAMetrics> agentExpectations = new HashMap<Integer, POIwithSAMetrics>();
		// HashMap<Integer, POIwithSAMetrics> masterExpectations;

		// get all the POIs near the agent
		HashMap<Integer, POI> poisNearTheAgent = masterAgent.getPOIsNear(context);
		//System.out.println("Number of POIs near the Agent:" + poisNearTheAgent.size());

		poisNearTheAgentWithMASAValues = masterAgent.getKnowledge(poisNearTheAgent);
		expectationsByGoal.addMasterAgentKnowledge(context.getGoal(), poisNearTheAgentWithMASAValues);

		noisyPOIs = masterAgent.getNoisyPOIs(poisNearTheAgent, context);

		int poiID;
		POIwithSAMetrics masterPOISAValues = null, poiWithNewSAValues = null, temp = null;
		double resultForSurpriseDayOff = 0.0, resultForSurprisePrice = 0.0, resultForSurpriseSchedule = 0.0;
		double resultForUncertaintyDayOff = 0.0, resultForUncertaintyPrice = 0.0, resultForUncertaintySchedule = 0.0;
		HashMap<Integer, POI> newPOIsToBeStored = new HashMap<Integer, POI>();
		POI newPOItoBeStored1 = null;
		POIwithSAMetrics newPOItoBeStored2 = null;

		for (POI poi : poisNearTheAgent.values()) {
			poiID = poi.getPoiID();
			//System.out.println("POI ID: " + poiID + " GOAL: " + context.getGoal());
			// 1) Agent's past knowledge about the surprise (an average for all
			// the parameters)
			userModelSurpriseKnowledge = agent.getAgentPastKnowledgeAboutSurprise(email, context.getGoal());
			//System.out.println(userModelSurpriseKnowledge.toString());
			userModelUncertaintyKnowledge = agent.getAgentPastKnowledgeAboutUncertainty(email, context.getGoal());

			// ***
			temp = new POIwithSAMetrics(poi, userModelSurpriseKnowledge.getSurprisePrice(), userModelSurpriseKnowledge.getSurpriseDayOff(),
					userModelSurpriseKnowledge.getSurpriseSchedule(), userModelUncertaintyKnowledge.getUncertaintyPrice(),
					userModelUncertaintyKnowledge.getUncertaintyDayOff(), userModelUncertaintyKnowledge.getUncertaintySchedule());
			userModelTemp.put(poiID, temp);
			// ***

			// 2) real Surprise values from the Master Agent for all the
			// parameters
			masterPOISAValues = poisNearTheAgentWithMASAValues.get(poiID);
			// System.out.println("A avaliar: ");
			// System.out.println(masterPOISAValues.to_String());

			// 3) calculate the surprise values for the three parameters
			// (DayOff, Price and Schedule). The Evaluator will confront the
			// Agent's Knowledge with the Master Agent's Knowledge
			resultForSurpriseDayOff = sEvaluator.evaluatingDaysOff(userModelSurpriseKnowledge.getSurpriseDayOff(), masterPOISAValues.getSurpriseDayOff());
			resultForSurprisePrice = sEvaluator.evaluatingPrice(userModelSurpriseKnowledge.getSurprisePrice(), masterPOISAValues.getSurprisePrice());
			resultForSurpriseSchedule = sEvaluator
					.evaluatingSchedule(userModelSurpriseKnowledge.getSurpriseSchedule(), masterPOISAValues.getSurpriseSchedule());

			resultForUncertaintyDayOff = uEvaluator.evaluatingDaysOff(userModelUncertaintyKnowledge.getUncertaintyDayOff(),
					masterPOISAValues.getUncertaintyDayOff());
			resultForUncertaintyPrice = uEvaluator
					.evaluatingPrice(userModelUncertaintyKnowledge.getUncertaintyPrice(), masterPOISAValues.getUncertaintyPrice());
			resultForUncertaintySchedule = uEvaluator.evaluatingSchedule(userModelUncertaintyKnowledge.getUncertaintySchedule(),
					masterPOISAValues.getUncertaintySchedule());

			// 4) creating the new POI that will e stored in the Agent Knowledge
			// base.
			// It will stored the POI Information as well as the resulted
			// surprise's values for the three parameters
			newPOItoBeStored1 = new POI(poi.getPoiName(), poi.getPoiID(), poi.getNumCheckins(), poi.getPrice(), poi.getLocation(), poi.getCategory(),
					poi.getSubCategory(), poi.getDaysOn(), poi.getDaysOff());
			newPOItoBeStored1.setSurpriseTOdayOff(resultForSurpriseDayOff);
			newPOItoBeStored1.setSurpriseTOprice(resultForSurprisePrice);
			newPOItoBeStored1.setSurpriseTOschedule(resultForSurpriseSchedule);

			newPOItoBeStored1.setUncertaintyTOdayOff(resultForUncertaintyDayOff);
			newPOItoBeStored1.setUncertaintyTOprice(resultForUncertaintyPrice);
			newPOItoBeStored1.setUncertaintyTOschedule(resultForUncertaintySchedule);

			newPOIsToBeStored.put(poiID, newPOItoBeStored1);

			// System.out.println("\n ***---> "+newPOItoBeStored1.to_StringSAValues());

			// 5) POI Information given by the Master Agent that will be stored
			// in the Agent's Knowledge base. This Knowledge has noise!
			newPOItoBeStored2 = agent.getSAValuesForPOI(newPOItoBeStored1);

			// System.out.println("\n ###---> "+newPOItoBeStored2.to_String());

			// storing the surprise attention values
			poiWithNewSAValues = new POIwithSAMetrics(noisyPOIs.get(poiID), newPOItoBeStored2.getSurprisePrice(), newPOItoBeStored2.getSurpriseDayOff(),
					newPOItoBeStored2.getSurpriseSchedule(), newPOItoBeStored2.getUncertaintyPrice(), newPOItoBeStored2.getUncertaintyDayOff(),
					newPOItoBeStored2.getUncertaintySchedule());

			agentExpectations.put(poiID, poiWithNewSAValues);
		}
		expectationsByGoal.addSelectiveAttentionValues(context.getGoal(), newPOIsToBeStored);
		expectationsByGoal.addExpectationsAgent(context.getGoal(), agentExpectations);
		expectationsByGoal.addUserModel(context.getGoal(), userModelTemp);
	}

	// para guardar o feedback do utilizador
	public boolean saveFeedback() {
		return true;
	}

}
